import { fetchCapabilityDocumentation } from '@/service'
import WMS from '@/utils/resolveWMS'
import ExceptionLogger from '@/utils/errorHandler'
import { getCoordinateSystemProjInfo, computedLeafletCRSDefined, computedOpenlayersCRSDefined } from '@/utils/coordinateSystem'

export const useWMSStore = defineStore('wms-store', {
  state: () => {
    return {
      fetchURL: '',
      token: false,
      tokenInfo: {},
      wmsInfo: {},
      currentLayer: {},
      isUseName: false,
      getCapabilitiesURL: '',
      getMapURL: '',
      boundingBox: [],
      leafletAddCode: '',
      openlayersAddCode: '',
      cesiumAddCode: '',
      supermap3dAddCode: ''
    }
  },
  actions: {
    async initWMSInfo(wmsURL) {
      this.fetchURL = wmsURL
      // 判断有无token, 并获取token值
      const requestURL = new URL(wmsURL)
      const queryParams = new URLSearchParams(requestURL.search)
      this.token = queryParams.has('token') || queryParams.has('key')
      if (this.token) {
        const tokenType = queryParams.has('token') ? 'token' : 'key'
        const tokenValue = queryParams.get(tokenType)
        this.tokenInfo = {
          type: tokenType,
          value: tokenValue
        }
      }
      const wms = new WMS(await fetchCapabilityDocumentation(this.fetchURL))
      this.wmsInfo = wms.info
      this.getCapabilitiesURL = wmsURL
      this.getMapURL = this.token ? `${wms.info.getMapURL}?${this.tokenInfo.type}=${this.tokenInfo.value}` : `${wms.info.getMapURL}`
      // 默认使用地图初始加载
      this.currentLayer = wms.info.layer[0]
      // 根据layer的title判断是否有图层名跟地图名重复的情况，重复时用name标识layer，否则用title标识layer
      this.isUseName = new Set(wms.info.layer.map((item) => item.title)).size !== wms.info.layer.map((item) => item.title).length
    },

    initWMSInfoByFile(wmsFile) {
      const wms = new WMS(wmsFile)
      this.wmsInfo = wms.info
      this.getCapabilitiesURL = wms.info.getCapabilitiesURL
      this.getMapURL = wms.info.getMapURL
      this.currentLayer = wms.info.layer[0]
      this.isUseName = new Set(wms.info.layer.map((item) => item.title)).size !== wms.info.layer.map((item) => item.title).length
    },

    setCurrentLayer(layerName) {
      this.currentLayer = Array.from(this.wmsInfo.layer).find((item) => item.title === layerName)
    },

    async setLeafletAddCode() {
      const match = JSON.stringify(this.currentLayer.boundingBox.srs).match(/EPSG:(\d+)/)
      const epsgcodeValue = match ? parseInt(match[1], 10) : null
      if (epsgcodeValue < 2000 || epsgcodeValue > 9040) {
        this.leafletAddCode = ''
        return ExceptionLogger.logException(`EPSG code为 ${epsgcodeValue}, 无法解析坐标系, 请检查数据来源是否正确!`)
      }
      const proj4Defined = await getCoordinateSystemProjInfo(epsgcodeValue)
      const layers = this.isUseName ? this.currentLayer.name : this.currentLayer.title
      this.boundingBox = [
        [Number(this.currentLayer.LatLonBoundingBox.minx), Number(this.currentLayer.LatLonBoundingBox.miny)],
        [Number(this.currentLayer.LatLonBoundingBox.maxx), Number(this.currentLayer.LatLonBoundingBox.maxy)]
      ]

      switch (proj4Defined) {
        case 4326:
          this.leafletAddCode = `
window.LMap_wms = L.map(document.getElementById('LMap_wms'), {
    crs: L.CRS.EPSG4326,
})
new L.TileLayer.WMS('${this.getMapURL}', {
    layers: '${layers}',
    format: 'image/png',
    version: '${this.wmsInfo.wmsType}',
    transparent: true,
    noWrap: true
}).addTo(LMap_wms)
LMap_wms.fitBounds(L.latLngBounds([[${this.boundingBox[0][1]}, ${this.boundingBox[0][0]}],[${this.boundingBox[1][1]}, ${this.boundingBox[1][0]}]]))
`
          break

        case 3857:
          this.leafletAddCode = `
window.LMap_wms = L.map(document.getElementById('LMap_wms'), {
    crs: L.CRS.EPSG3857,
})
new L.TileLayer.WMS('${this.getMapURL}', {
    layers: '${layers}',
    format: 'image/png',
    version: '${this.wmsInfo.wmsType}',
    transparent: true,
    noWrap: true
}).addTo(LMap_wms)
LMap_wms.fitBounds(L.latLngBounds([[${this.boundingBox[0][1]}, ${this.boundingBox[0][0]}],[${this.boundingBox[1][1]}, ${this.boundingBox[1][0]}]]))
`
          break

        default:
          const crs = await computedLeafletCRSDefined(epsgcodeValue)
          const bboxRegex = /bbox=([\d.]+),([\d.]+),([\d.]+),([\d.]+)/
          if (this.wmsInfo.wmsType === '1.1.1') {
            this.leafletAddCode = `
${proj4Defined}
window.LMap_wms = L.map(document.getElementById('LMap_wms'), {
    crs: ${crs}
})
new L.TileLayer.WMS('${this.getMapURL}', {
    layers: '${layers}',
    format: 'image/png',
    version: '${this.wmsInfo.wmsType}',
    transparent: true,
    noWrap: true
}).addTo(LMap_wms)
LMap_wms.fitBounds(L.latLngBounds([[${this.boundingBox[0][1]}, ${this.boundingBox[0][0]}],[${this.boundingBox[1][1]}, ${this.boundingBox[1][0]}]]))
`
          } else {
            this.leafletAddCode = `
${proj4Defined}
window.LMap_wms = L.map(document.getElementById('LMap_wms'), {
    crs: ${crs},
})
const wmsLayer = new L.TileLayer.WMS('${this.getMapURL}', {
    layers: '${layers}',
    format: 'image/png',
    version: '${this.wmsInfo.wmsType}',
    transparent: true,
    noWrap: true
})
wmsLayer.on('tileloadstart', function (e) {
  e.tile.src = e.tile.src.replace(${bboxRegex}, function (match, minX, minY, maxX, maxY) {
    return 'bbox=' + minY + ',' + minX + ',' + maxY + ',' + maxX;
  });
});
wmsLayer.addTo(LMap_wms)
LMap_wms.fitBounds(L.latLngBounds([[${this.boundingBox[0][1]}, ${this.boundingBox[0][0]}],[${this.boundingBox[1][1]}, ${this.boundingBox[1][0]}]]))
`
          }

          break
      }
    },

    async setOpenlayersAddCode() {
      const match = JSON.stringify(this.currentLayer.boundingBox.srs).match(/EPSG:(\d+)/)
      const epsgcodeValue = match ? parseInt(match[1], 10) : null
      if (epsgcodeValue < 2000 || epsgcodeValue > 9040) {
        this.openlayersAddCode = ''
        return ExceptionLogger.logException(`EPSG code为 ${epsgcodeValue}, 无法解析坐标系, 请检查数据来源是否正确!`)
      }
      const proj4Defined = await getCoordinateSystemProjInfo(epsgcodeValue)
      const layers = this.isUseName ? this.currentLayer.name : this.currentLayer.title
      switch (proj4Defined) {
        case 4326:
          this.boundingBox =
            this.wmsInfo.wmsType === '1.1.1'
              ? [
                  [Number(this.currentLayer.boundingBox.minx), Number(this.currentLayer.boundingBox.miny)],
                  [Number(this.currentLayer.boundingBox.maxx), Number(this.currentLayer.boundingBox.maxy)]
                ]
              : [
                  [Number(this.currentLayer.boundingBox.miny), Number(this.currentLayer.boundingBox.minx)],
                  [Number(this.currentLayer.boundingBox.maxy), Number(this.currentLayer.boundingBox.maxx)]
                ]
          this.openlayersAddCode = `
window.olMap_wms = new Map({
  target: document.getElementById('olMap_wms'),
  view: new View({
    projection: 'EPSG:4326',
    multiWorld: true
  })
})
const tileLayer = new TileLayer({
    source: new TileWMS({
    url: '${this.getMapURL}',
    params: {
      LAYERS: '${layers}',
      FORMAT: 'image/png',
      VERSION: '${this.wmsInfo.wmsType}'
    }
  })
})
olMap_wms.addLayer(tileLayer)
olMap_wms.getView().fit([${this.boundingBox[0][0]}, ${this.boundingBox[0][1]}, ${this.boundingBox[1][0]}, ${this.boundingBox[1][1]}])
`
          break

        case 3857:
          this.boundingBox = [
            [Number(this.currentLayer.boundingBox.minx), Number(this.currentLayer.boundingBox.miny)],
            [Number(this.currentLayer.boundingBox.maxx), Number(this.currentLayer.boundingBox.maxy)]
          ]
          this.openlayersAddCode = `
window.olMap_wms = new Map({
  target: document.getElementById('olMap_wms'),
  view: new View({
    projection: 'EPSG:3857',
    multiWorld: true
  })
})
const tileLayer = new TileLayer({
    source: new TileWMS({
    url: '${this.getMapURL}',
    params: {
      LAYERS: '${layers}',
      FORMAT: 'image/png',
      VERSION: '${this.wmsInfo.wmsType}'
    }
  })
})
olMap_wms.addLayer(tileLayer)
olMap_wms.getView().fit([${this.boundingBox[0][0]}, ${this.boundingBox[0][1]}, ${this.boundingBox[1][0]}, ${this.boundingBox[1][1]}])
`
          break

        default:
          this.boundingBox =
            this.wmsInfo.wmsType === '1.1.1'
              ? [
                  [Number(this.currentLayer.boundingBox.minx), Number(this.currentLayer.boundingBox.miny)],
                  [Number(this.currentLayer.boundingBox.maxx), Number(this.currentLayer.boundingBox.maxy)]
                ]
              : [
                  [Number(this.currentLayer.boundingBox.miny), Number(this.currentLayer.boundingBox.minx)],
                  [Number(this.currentLayer.boundingBox.maxy), Number(this.currentLayer.boundingBox.maxx)]
                ]
          const crs = await computedOpenlayersCRSDefined(epsgcodeValue, this.wmsInfo.wmsType)
          this.openlayersAddCode = `
${proj4Defined}
window.olMap_wms = new Map({
  target: document.getElementById('olMap_wms'),
  view: new View({
    projection: ${crs},
    multiWorld: true
  })
})
const tileLayer = new TileLayer({
    source: new TileWMS({
    url: '${this.getMapURL}',
    params: {
      LAYERS: '${layers}',
      FORMAT: 'image/png',
      VERSION: '${this.wmsInfo.wmsType}'
    }
  })
})
olMap_wms.addLayer(tileLayer)
olMap_wms.getView().fit([${this.boundingBox[0][0]}, ${this.boundingBox[0][1]}, ${this.boundingBox[1][0]}, ${this.boundingBox[1][1]}])
`
          break
      }
    },

    async setSuperMap3DAddCode() {
      const match = JSON.stringify(this.currentLayer.boundingBox.srs).match(/EPSG:(\d+)/)
      const epsgcodeValue = match ? parseInt(match[1], 10) : null
      if (epsgcodeValue < 2000 || epsgcodeValue > 9040) {
        this.supermap3dAddCode = ''
        return ExceptionLogger.logException(`EPSG code为 ${epsgcodeValue}, 无法解析坐标系, 请检查数据来源是否正确!`)
      }
      const proj4Defined = await getCoordinateSystemProjInfo(epsgcodeValue)
      const coordinateSystem = this.wmsInfo.wmsType === '1.1.1' ? 'srs' : 'crs'
      const layers = this.isUseName ? this.currentLayer.name : this.currentLayer.title
      this.boundingBox = [
        [Number(this.currentLayer.LatLonBoundingBox.minx), Number(this.currentLayer.LatLonBoundingBox.miny)],
        [Number(this.currentLayer.LatLonBoundingBox.maxx), Number(this.currentLayer.LatLonBoundingBox.maxy)]
      ]
      switch (proj4Defined) {
        case 4326:
          this.supermap3dAddCode = `
smViewer_wms.scene.imageryLayers.add(
  new SuperMap3D.ImageryLayer(
    new SuperMap3D.WebMapServiceImageryProvider({
      url: '${this.getMapURL}',
      layers: '${layers}',
      parameters: {
        service: 'WMS',
        version: '${this.wmsInfo.wmsType}',
        format: 'image/png',
        transparent: true
      },
      tilingScheme: new SuperMap3D.GeographicTilingScheme()
    })
  )
)
smViewer_wms.scene.camera.flyTo({
  destination: new SuperMap3D.Rectangle(SuperMap3D.Math.toRadians(${this.boundingBox[0][0]}), SuperMap3D.Math.toRadians(${this.boundingBox[0][1]}), SuperMap3D.Math.toRadians(${this.boundingBox[1][0]}), SuperMap3D.Math.toRadians(${this.boundingBox[1][1]})),
  duration: 2
})
`
          break

        case 3857:
          this.supermap3dAddCode = `
smViewer_wms.scene.imageryLayers.add(
  new SuperMap3D.ImageryLayer(
    new SuperMap3D.WebMapServiceImageryProvider({
      url: '${this.getMapURL}',
      layers: '${layers}',
      parameters: {
        service: 'WMS',
        version: '${this.wmsInfo.wmsType}',
        ${coordinateSystem}: 'EPSG:3857',
        format: 'image/png',
        transparent: true
      },
      tilingScheme: new SuperMap3D.WebMercatorTilingScheme()
    })
  )
)
smViewer_wms.scene.camera.flyTo({
  destination: new SuperMap3D.Rectangle(SuperMap3D.Math.toRadians(${this.boundingBox[0][0]}), SuperMap3D.Math.toRadians(${this.boundingBox[0][1]}), SuperMap3D.Math.toRadians(${this.boundingBox[1][0]}), SuperMap3D.Math.toRadians(${this.boundingBox[1][1]})),
  duration: 2
})
`
          break

        default:
          // 非 3857 4326 坐标系，待完善
          this.supermap3dAddCode = `
smViewer_wms.scene.imageryLayers.add(
  new SuperMap3D.ImageryLayer(
    new SuperMap3D.WebMapServiceImageryProvider({
      url: '${this.getMapURL}',
      layers: '${layers}',
      parameters: {
        service: 'WMS',
        version: '${this.wmsInfo.wmsType}',
        format: 'image/png',
        transparent: true
      },
      tilingScheme: new SuperMap3D.GeographicTilingScheme()
    })
  )
)
smViewer_wms.scene.camera.flyTo({
  destination: new SuperMap3D.Rectangle(SuperMap3D.Math.toRadians(${this.boundingBox[0][0]}), SuperMap3D.Math.toRadians(${this.boundingBox[0][1]}), SuperMap3D.Math.toRadians(${this.boundingBox[1][0]}), SuperMap3D.Math.toRadians(${this.boundingBox[1][1]})),
  duration: 2
})
`
          break
      }
    },

    async setCesiumAddCode() {
      const match = JSON.stringify(this.currentLayer.boundingBox.srs).match(/EPSG:(\d+)/)
      const epsgcodeValue = match ? parseInt(match[1], 10) : null
      if (epsgcodeValue < 2000 || epsgcodeValue > 9040) {
        this.cesiumAddCode = ''
        return ExceptionLogger.logException(`EPSG code为 ${epsgcodeValue}, 无法解析坐标系, 请检查数据来源是否正确!`)
      }
      const proj4Defined = await getCoordinateSystemProjInfo(epsgcodeValue)
      const coordinateSystem = this.wmsInfo.wmsType === '1.1.1' ? 'srs' : 'crs'
      const layers = this.isUseName ? this.currentLayer.name : this.currentLayer.title
      this.boundingBox = [
        [Number(this.currentLayer.LatLonBoundingBox.minx), Number(this.currentLayer.LatLonBoundingBox.miny)],
        [Number(this.currentLayer.LatLonBoundingBox.maxx), Number(this.currentLayer.LatLonBoundingBox.maxy)]
      ]
      const query_layers = this.wmsInfo.layer.slice(1).map((layer) => layer.title)
      const getFeatureInfoParameters = {
        info_format: 'application/geojson',
        query_layers: JSON.stringify(query_layers)
      }
      switch (proj4Defined) {
        case 4326:
          this.cesiumAddCode = `
viewer_wms.scene.imageryLayers.add(
  new Cesium.ImageryLayer(
    new Cesium.WebMapServiceImageryProvider({
      url: '${this.getMapURL}',
      layers: '${layers}',
      parameters: {
        service: 'WMS',
        version: '${this.wmsInfo.wmsType}',
        format: 'image/png',
        transparent: true
      },
      getFeatureInfoParameters: {
        info_format: '${getFeatureInfoParameters.info_format}',
        version: '${this.wmsInfo.wmsType}',
        query_layers: ${getFeatureInfoParameters.query_layers}
      },
      enablePickFeatures: true,
      tilingScheme: new Cesium.GeographicTilingScheme()
    })
  )
)

viewer_wms.scene.camera.flyTo({
  destination: new Cesium.Rectangle(Cesium.Math.toRadians(${this.boundingBox[0][0]}), Cesium.Math.toRadians(${this.boundingBox[0][1]}), Cesium.Math.toRadians(${this.boundingBox[1][0]}), Cesium.Math.toRadians(${this.boundingBox[1][1]})),
  duration: 0
})`
          break

        case 3857:
          this.cesiumAddCode = `
viewer_wms.scene.imageryLayers.add(
  new Cesium.ImageryLayer(
    new Cesium.WebMapServiceImageryProvider({
      url: '${this.getMapURL}',
      layers: '${layers}',
      parameters: {
        service: 'WMS',
        version: '${this.wmsInfo.wmsType}',
        ${coordinateSystem}: 'EPSG:3857',
        format: 'image/png',
        transparent: true
      },
      getFeatureInfoParameters: {
        info_format: '${getFeatureInfoParameters.info_format}',
        version: '${this.wmsInfo.wmsType}',
        query_layers: ${getFeatureInfoParameters.query_layers}
      },
      enablePickFeatures: true,
      tilingScheme: new Cesium.WebMercatorTilingScheme()
    })
  )
)

viewer_wms.scene.camera.flyTo({
  destination: new Cesium.Rectangle(Cesium.Math.toRadians(${this.boundingBox[0][0]}), Cesium.Math.toRadians(${this.boundingBox[0][1]}), Cesium.Math.toRadians(${this.boundingBox[1][0]}), Cesium.Math.toRadians(${this.boundingBox[1][1]})),
  duration: 0
})`
          break

        default:
          // 非 3857 4326 坐标系，待完善
          this.cesiumAddCode = `
viewer_wms.scene.imageryLayers.add(
  new Cesium.ImageryLayer(
    new Cesium.WebMapServiceImageryProvider({
      url: '${this.getMapURL}',
      layers: '${layers}',
      parameters: {
        service: 'WMS',
        version: '${this.wmsInfo.wmsType}',
        format: 'image/png',
        transparent: true
      },
      getFeatureInfoParameters: {
        info_format: '${getFeatureInfoParameters.info_format}',
        version: '${this.wmsInfo.wmsType}',
        query_layers: ${getFeatureInfoParameters.query_layers}
      },
      enablePickFeatures: true,
      tilingScheme: new Cesium.GeographicTilingScheme()
    })
  )
)

viewer_wms.scene.camera.flyTo({
  destination: new Cesium.Rectangle(Cesium.Math.toRadians(${this.boundingBox[0][0]}), Cesium.Math.toRadians(${this.boundingBox[0][1]}), Cesium.Math.toRadians(${this.boundingBox[1][0]}), Cesium.Math.toRadians(${this.boundingBox[1][1]})),
  duration: 0
})`
          break
      }
    }
  }
})
